#include "machine_manifest.h"
#include "logger.h"

#include "nosal/log/logger.h"
#include "nosal/log/logging.h"

#include <algorithm>
#include <iterator>

namespace netaos {
namespace nosal {
namespace exec {
namespace internal {
namespace config {

namespace {
netaos::nosal::log::Logger& GetLogger()
{
    static netaos::nosal::log::Logger& logger
        = netaos::nosal::log::CreateLogger("MAMN", "Machine Manifest", netaos::nosal::exec::internal::kLogLevel);
    return logger;
}
}  // namespace

const char kStateOff[] = "Off";
const char kStateMachineStartup[] = "Startup";
const char kStateMachineShutdown[] = "Shutdown";
const char kStateMachineRestart[] = "Restart";
const char kStateMachineVerify[] = "Verify";

MachineManifest::MachineManifest(std::string manifestPath)
{
    constexpr auto kMachineStatesKey = "states";
    constexpr auto kFunctionGroupsKey = "function_groups";
    constexpr auto kResourceGroupsKey = "resource_groups";
    constexpr auto kDefaultApplicationTimeout = "default_application_timeout";
    constexpr auto kEnvironmentVariables = "environment";
#if 0
    auto manifestRes = apd::manifestreader::OpenManifest(manifestPath);

    if (!manifestRes) {
        GetLogger().LogError() << "Error opening manifest" << manifestPath;
        return;
    }
    auto manifest = std::move(manifestRes).Value();

    auto defaultProcessTimeoutRes = manifest->GetValue<EnterExitTimeout>(kDefaultApplicationTimeout);
    defaultProcessTimeout_ = defaultProcessTimeoutRes.ValueOr(EnterExitTimeout());

    auto environmentVariablesRes = manifest->GetArray<netaos::nosal::core::String>(kEnvironmentVariables);
    environmentVariables_ = environmentVariablesRes.ValueOr(netaos::nosal::core::Vector<netaos::nosal::core::String>());

    auto statesRes = manifest->GetArray<State>(kMachineStatesKey);
    if (statesRes) {
        machineStates_.reserve(
            statesRes.Value().size() + 4U);  /// reserve additional space for the four mandatory Machine States
        std::copy(statesRes.Value().begin(), statesRes.Value().end(), std::back_inserter(machineStates_));

        if (std::find_if(
                machineStates_.begin(), machineStates_.end(), [](State& s) { return s.GetName() == "Startup"; })
            == machineStates_.end()) {
            GetLogger().LogInfo() << "Add missing Startup Machine State";
            machineStates_.emplace_back(kStateMachineStartup);
        }
        if (std::find_if(
                machineStates_.begin(), machineStates_.end(), [](State& s) { return s.GetName() == "Shutdown"; })
            == machineStates_.end()) {
            GetLogger().LogInfo() << "Add missing Shutdown Machine State";
            machineStates_.emplace_back(kStateMachineShutdown);
        }
        if (std::find_if(
                machineStates_.begin(), machineStates_.end(), [](State& s) { return s.GetName() == "Restart"; })
            == machineStates_.end()) {
            GetLogger().LogInfo() << "Add missing Restart Machine State";
            machineStates_.emplace_back(kStateMachineRestart);
        }
        if (std::find_if(machineStates_.begin(), machineStates_.end(), [](State& s) { return s.GetName() == "Verify"; })
            == machineStates_.end()) {
            GetLogger().LogInfo() << "Add missing Verify Machine State";
            machineStates_.emplace_back(kStateMachineVerify);
        }
    } else {
        GetLogger().LogError() << "Error in Machine State Extraction. Adding mandatory Machine States Startup, "
                                  "Shutdown, Restart and Verify.";
        machineStates_.emplace_back(kStateMachineStartup);
        machineStates_.emplace_back(kStateMachineShutdown);
        machineStates_.emplace_back(kStateMachineRestart);
        machineStates_.emplace_back(kStateMachineVerify);
    }

    auto functionGroupsRes = manifest->GetArray<FunctionGroup>(kFunctionGroupsKey);
    if (functionGroupsRes) {
        functionGroups_ = std::move(functionGroupsRes).Value();
    }

    auto resourceGroupsRes = manifest->GetArray<ResourceGroup>(kResourceGroupsKey);
    if (resourceGroupsRes) {
        resourceGroups_ = std::move(resourceGroupsRes).Value();
    }
#endif
}

}  // namespace config
}  // namespace internal
}  // namespace exec
}  // namespace nosal
}  // namespace netaos
